classdef PID_gui < hgsetget
    %PID_GUI Frontend for tuning up a software controlled PID
    %   Frontend for a software controlled PID which includes inputs for
    %   gains, plotted error as a function of time, and FFT of the error as
    %   a function of time, log file save location, etc.
    
    properties
        myTopFigure = [];
        myTitlePanel = [];
        myPanel = [];
        myPID;
        myPID2;
        myName;
        myPlotHandle = [];
        myFFTPlotHandle = [];
        myKp = [];
        myTi = [];
        myTd = [];
        myDeltaT = [];
        mySetPoint = [];
        
        myKp2 = [];
        myTi2 = [];
        myTd2 = [];
        myDeltaT2 = [];
        mySetPoint2 = [];
        myEnableBox = [];
    end
    
    methods
        function obj = PID_gui(topFig, parentObj, myName, initValues)
            obj.myTopFigure = topFig;
            obj.myName = myName;
            obj.myPID = PID.PID(1,initValues.kP1,initValues.Ti1,initValues.Td1,10);
            obj.myPID2 = PID.PID(1,initValues.kP2,initValues.Ti2,initValues.Td2,10);
            obj.myTitlePanel = uiextras.Panel('Parent', parentObj, ...
                'Title', ['PID ' num2str(myName)]);
            obj.myPanel = uiextras.HBox('Parent', obj.myTitlePanel, ...
                'Spacing', 5, ...
                'Padding', 5);
            mainControlsVB = uiextras.VBox('Parent', obj.myPanel, ...
                'Spacing', 5, ...
                'Padding', 5);
                gainsPanel = uiextras.Panel('Parent', mainControlsVB, ...
                    'Title', 'Gains');
                gainsHB = uiextras.HBox('Parent', gainsPanel);
                gainLabels = uiextras.VButtonBox('Parent', gainsHB, ...
                'Spacing', 2, ...
                'Padding', 2);
                    uiextras.Empty('Parent', gainLabels);
                    uicontrol('Parent', gainLabels, ...
                        'Style', 'text', ...
                        'FontSize', 6, ...
                        'String', 'Kp');
                    uicontrol('Parent', gainLabels, ...
                        'Style', 'text', ...
                        'FontSize', 6, ...
                        'String', 'Ti (s)');
                    uicontrol('Parent', gainLabels, ...
                        'Style', 'text', ...
                        'FontSize', 6, ...
                        'String', 'Td (s)');
                    uicontrol('Parent', gainLabels, ...
                        'Style', 'text', ...
                        'FontSize', 6, ...
                        'String', 'Set Point');
                    uicontrol('Parent', gainLabels, ...
                        'Style', 'text', ...
                        'FontSize', 6, ...
                        'String', 'Delta t (s)');
                gainsEdits = uiextras.VButtonBox('Parent', gainsHB, ...
                'Spacing', 2, ...
                'Padding', 2);
                    uicontrol('Parent', gainsEdits, ...
                        'Style', 'text', ...
                        'FontSize', 6, ...
                        'String', 'PID1');
                    obj.myKp = uicontrol('Parent', gainsEdits, ...
                        'Style', 'edit', ...
                        'Tag', 'kP', ...
                        'String', num2str(initValues.kP1));
                    obj.myTi = uicontrol('Parent', gainsEdits, ...
                        'Style', 'edit', ...
                        'Tag', 'tI', ...
                        'String', num2str(initValues.Ti1));
                    obj.myTd = uicontrol('Parent', gainsEdits, ...
                        'Style', 'edit', ...
                        'Tag', 'tD', ...
                        'String', num2str(initValues.Td1));
                    obj.mySetPoint = uicontrol('Parent', gainsEdits, ...
                        'Style', 'edit', ...
                        'Tag', 'setPoint', ...
                        'String', '0');
                    obj.myDeltaT = uicontrol('Parent', gainsEdits, ...
                        'Style', 'edit', ...
                        'Tag', 'deltaT', ...
                        'String', num2str(initValues.delta));
               gainsEdits2 = uiextras.VButtonBox('Parent', gainsHB, ...
                   'Spacing', 2, ...
                   'Padding', 2);
                    uicontrol('Parent', gainsEdits2, ...
                        'Style', 'text', ...
                        'FontSize', 6, ...
                        'String', 'PID2');
                    obj.myKp2 = uicontrol('Parent', gainsEdits2, ...
                        'Style', 'edit', ...
                        'Tag', 'kP2', ...
                        'String', num2str(initValues.kP2));
                    obj.myTi2 = uicontrol('Parent', gainsEdits2, ...
                        'Style', 'edit', ...
                        'Tag', 'tI2', ...
                        'String', num2str(initValues.Ti2));
                    obj.myTd2 = uicontrol('Parent', gainsEdits2, ...
                        'Style', 'edit', ...
                        'Tag', 'tD2', ...
                        'String', num2str(initValues.Td2));
                    obj.mySetPoint2 = uicontrol('Parent', gainsEdits2, ...
                        'Style', 'edit', ...
                        'Tag', 'setPoint2', ...
                        'String', '0');
                    obj.myDeltaT2 = uicontrol('Parent', gainsEdits2, ...
                        'Style', 'edit', ...
                        'Tag', 'deltaT2', ...
                        'String', num2str(initValues.delta));
                        pidButtons = uiextras.HButtonBox('Parent', mainControlsVB);
                        obj.myEnableBox = uicontrol( ...
                            'Parent', pidButtons, ...
                            'Style', 'checkbox', ...
                            'String', 'Enable PID', ...
                            'Tag', 'pidEnabled', ...
                            'Value', 1);
                        uicontrol( ...
                            'Parent', pidButtons, ...
                            'Style', 'pushbutton', ...
                            'String', 'BodePlot', ...
                            'Callback', @obj.createBodePlot_Callback, ...
                            'Tag', 'createBodePlot');
                        tempPAN = obj.myPanel; %Needed for older matlabs
                    errPlot = axes( 'Parent', tempPAN, ...
                        'Tag', ['err_PID' obj.myName ], ...
                        'ActivePositionProperty', 'OuterPosition');
                        title(errPlot, 'Error Signal');
                    errFFT = axes( 'Parent', tempPAN, ...
                        'Tag', ['err_FFT' obj.myName ], ...
                        'ActivePositionProperty', 'OuterPosition');
                        title(errFFT, 'SS Error Amp Spectrum');
        end
        
        function updateMyPlots(obj, newErr, runNum, plotSize)
            myHandles = guidata(obj.myTopFigure);
            tempPIDData = getappdata(obj.myTopFigure, ['PID' obj.myName 'Data']);
            if isempty(obj.myPlotHandle)
                obj.myPlotHandle = plot(myHandles.(['err_PID' obj.myName]), tempPIDData(end-plotSize:end), 'ok', 'LineWidth', 3);
                
                
                Fs = 1/str2double(get(obj.myDeltaT, 'String'));% Sampling frequency
                L = length(tempPIDData);    % Length of signal
                NFFT = 2^nextpow2(L);       % Next power of 2 from length of y
                Y = fft(tempPIDData,NFFT)/L;
                f = Fs/2*linspace(0,1,NFFT/2+1);
                % Plot single-sided amplitude spectrum.
                obj.myFFTPlotHandle = plot(myHandles.(['err_FFT' obj.myName]), f, 2*abs(Y(1:NFFT/2+1)), 'LineWidth', 1);
            elseif runNum > 2
                set(obj.myPlotHandle, 'YData', tempPIDData(end-plotSize:end));
                refreshdata(obj.myPlotHandle);
                
                
                Fs = 1/str2double(get(obj.myDeltaT, 'String'));% Sampling frequency
                L = length(tempPIDData);    % Length of signal
                NFFT = 2^nextpow2(L);       % Next power of 2 from length of y
                Y = fft(tempPIDData,NFFT)/L;
                f = Fs/2*linspace(0,1,NFFT/2+1);
                set(obj.myFFTPlotHandle, 'YData', 2*abs(Y(1:NFFT/2+1)));
                set(obj.myFFTPlotHandle, 'XData', f);
                refreshdata(obj.myFFTPlotHandle);
                drawnow;
            end
            guidata(obj.myTopFigure, myHandles);
        end
        function getSaveDir_Callback(obj, src, eventData)      
            myHandles = guidata(obj.myTopFigure);
            dirPath = uigetdir(['Z:\Sr3\data']);
            set(myHandles.saveDir, 'String', dirPath);
            guidata(obj.myTopFigure, myHandles);
        end
        function createBodePlot_Callback(obj, src, eventData)
            C = pidstd(str2double(get(obj.myKp, 'String')), str2double(get(obj.myTi, 'String')),str2double(get(obj.myTd, 'String')) ,'Ts',str2double(get(obj.myDeltaT, 'String')),'IFormula','Trapezoidal');
            C2 = pidstd(str2double(get(obj.myKp2, 'String')),str2double(get(obj.myTi2, 'String')),str2double(get(obj.myTd2, 'String')), 'Ts',str2double(get(obj.myDeltaT2, 'String')),'IFormula','Trapezoidal');
            P = bodeoptions;
            P.FreqUnits = 'Hz';
            figure;
            bodeplot(C2*C, P)
        end
    end
    
end

